﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//    StatusControl.cs
//
// Abstract:
//    
//    Displays the status checkboxes for the status condition.
//
//--

using System;
using System.Diagnostics;
using System.Drawing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using Microsoft.OfficeCommunicationsServer.Applications.Common;

namespace Microsoft.EnhancedReminders.OutlookAddIn
{
    /// <summary>
    /// Interaction logic for StatusControl.xaml
    /// </summary>
    public partial class StatusControl : UserControl
    {
        /// <summary>
        /// Command for CheckBox events.
        /// </summary>
        public readonly static RoutedCommand CheckBoxCommand = new RoutedCommand();

        private NotificationStatusCondition _statusCondition;

        private static readonly BitmapSource _onlineIcon = GetBitmapSource(Properties.Resources.presence_online);
        private static readonly BitmapSource _busyIcon = GetBitmapSource(Properties.Resources.presence_busy);
        private static readonly BitmapSource _doNotDisturbIcon = GetBitmapSource(Properties.Resources.presence_dnd);
        private static readonly BitmapSource _awayIcon = GetBitmapSource(Properties.Resources.presence_away);
        private static readonly BitmapSource _inactiveIcon = GetBitmapSource(Properties.Resources.presence_idle_online);
        private static readonly BitmapSource _idleBusyIcon = GetBitmapSource(Properties.Resources.presence_idle_busy);
        private static readonly BitmapSource _offlineIcon = GetBitmapSource(Properties.Resources.presence_offline);
        private static readonly BitmapSource _unknownIcon = GetBitmapSource(Properties.Resources.presence_unknown);

        /// <summary>
        /// ctor.
        /// </summary>
        public StatusControl()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Initialize the status checkboxes to the states specified by the the status condition
        /// Presence property.  The status control updates the Presence property as the state
        /// checkboxes are checked/unchecked so there is no explicit "return" value.
        /// </summary>
        /// <param name="statusCondition">The status condition.</param>
        public void Initialize(NotificationStatusCondition statusCondition)
        {
            Debug.Assert(statusCondition != null, "statusCondition");

            _statusCondition = statusCondition;

            InitializeCheckBox(checkBoxAvailable, _onlineIcon, PresenceStates);

            InitializeCheckBox(checkBoxBusy, _busyIcon, PresenceStates);

            InitializeCheckBox(checkBoxMeeting, _busyIcon, PresenceStates);
            
            InitializeCheckBox(checkBoxCall, _busyIcon, PresenceStates);
            
            InitializeCheckBox(checkBoxConference, _busyIcon, PresenceStates);
            
            InitializeCheckBox(checkBoxDoNotDisturb, _doNotDisturbIcon, PresenceStates);
            
            InitializeCheckBox(checkBoxBeRightBack, _awayIcon, PresenceStates);

            InitializeCheckBox(checkBoxAway, _awayIcon, PresenceStates);

            InitializeCheckBox(checkBoxInactive, _inactiveIcon, PresenceStates);

            InitializeCheckBox(checkBoxIdleBusy, _idleBusyIcon, PresenceStates);

            InitializeCheckBox(checkBoxOffline, _offlineIcon, PresenceStates);

            InitializeCheckBox(checkBoxUnknown,  _unknownIcon, PresenceStates);
        }

        /// <summary>
        /// Initialize a checkbox to its initial state and assign an icon bitmap.
        /// </summary>
        /// <param name="checkbox">The checkbox to initialize.</param>
        /// <param name="icon">The bitmap to display for this checkbox.</param>
        /// <param name="initialStates">The list of states that should be checked.</param>
        private static void InitializeCheckBox(CheckBox checkbox, BitmapSource icon, PresenceStates initialStates)
        {
            Debug.Assert(checkbox != null, "checkbox");
            Debug.Assert(icon != null, "icon");

            DockPanel dockPanel = Helpers.AssertCast<DockPanel>(checkbox.Content);

            Debug.Assert(dockPanel.Children != null, "dockPanel.Children");
            Debug.Assert(dockPanel.Children.Count > 0, "dockPanel.Children.Count");

            System.Windows.Controls.Image image = 
                Helpers.AssertCast<System.Windows.Controls.Image>(dockPanel.Children[0]);

            try
            {
                // Ignore the InvalidOperation thrown when run from unit tests.  This happens only in unit 
                // tests because image.Source can only be assigned on the UI thread.  If this occurs when
                // runing in the Outlook add-in it would be very noticeably broken (no presence icons visible)
                // so it would be overkill to assert that the exception is only thrown in unit tests.
                image.Source = icon;
            }
            catch (InvalidOperationException)   
            {}

            // Compare the state associated with the checkbox with the list of states to initialize.
            PresenceStates targetState = Helpers.AssertCast<PresenceStates>(checkbox.Tag);

            checkbox.IsChecked = (targetState & initialStates) != 0;
        }

        /// <summary>
        /// Convert a Bitmap image (as stored in resources) to a BitmapSource.
        /// </summary>
        private static BitmapSource GetBitmapSource(Bitmap bitmap)
        {
            Debug.Assert(bitmap != null, "bitmap");

            using (bitmap)
            {
                return Imaging.CreateBitmapSourceFromHBitmap(
                    bitmap.GetHbitmap(),
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    BitmapSizeOptions.FromEmptyOptions());
            }
        }

        /// <summary>
        /// Helper property to get/set the Presence field from the status condition.
        /// </summary>
        private PresenceStates PresenceStates
        {
            get
            {
                Debug.Assert(_statusCondition != null, "_statusCondition");

                return _statusCondition.Presence;
            }
            set
            {
                Debug.Assert(_statusCondition != null, "_statusCondition");

                _statusCondition.Presence = value;
            }
        }

        /// <summary>
        /// True if a status checkbox can be enabled.
        /// </summary>
        private void CheckStatusCheckboxCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            Debug.Assert(null != sender, "sender");
            Debug.Assert(e != null, "e");

            e.CanExecute = true;
        }

        /// <summary>
        /// Invoked when a status checkbox is checked or unchecked.  The presence status associated 
        /// with the checkbox is identified by the Tag property which is assigned a status by Initialize().
        /// </summary>
        private void CheckStatusCheckbox(object sender, ExecutedRoutedEventArgs e)
        {
            Debug.Assert(sender != null, "sender");
            Debug.Assert(e != null, "e");

            CheckBox checkbox = e.OriginalSource as CheckBox;

            Debug.Assert(checkbox != null, "checkbox");
            Debug.Assert(checkbox.Tag != null, "checkbox.Tag");

            PresenceStates targetState = (PresenceStates)checkbox.Tag;

            PresenceStates ^= targetState;
        }
    }
}
